# == Schema Information
# Schema version: 36
#
# Table name: issues
#
#  id             :integer       not null, primary key
#  issue_number   :integer       not null
#  volume_id      :integer       not null
#  created_at     :datetime      not null
#  updated_at     :datetime      not null
#  status         :integer       
#  date_published :datetime      
#  layout         :text          
#

# An Issue is the equivalent of a single printed newspaper
#
# An Issue has many sections and belongs to a Volume

class Issue < ActiveRecord::Base

#     this class variable stores the possible values for
#     status, i will prefer not to do it via a column in a db table of type
#     set, because implementations of this datatype are incompatible
#     across diferent dbms
  @@possible_statuses = {"published" => 1, "not published" => 2}.freeze

#   @@default_sections = ["Sports", "Arts"]
  @@default_sections = CUPOLA_CONFIG["default_sections"]

  belongs_to :volume
  has_many :sections
#     different number for sections within the same volume

  validates_uniqueness_of :issue_number, :scope => "volume_id"
  validates_presence_of :issue_number
  validates_presence_of :status
  validates_uniqueness_of :date_published

#     Validates the inclusion of a valid status
#     fixme:add a proper message
#     no need for this validation, is a list box
#     validates_inclusion_of :status, :in => [1,2], :message=>"should be: #{@@possible_statuses}"
#     look for issues in a volume

  def self.find_by_volume(volume_id)
    self.find :all, :conditions => ["volume_id = ?", volume_id], :order => "created_at DESC"
  end
  
  def self.find_by_date_published(date)
    res = self.find :first, :conditions => ["date_published = ?  and date_published <= NOW()", date], :order => "created_at DESC", :limit => 1
  end 

#     look for not published issues, where chandges could be made
  def self.find_not_published
      self.find :all, :conditions => "status = '#{@@possible_statuses["not published"]}' "
  end

#     todo:look for the last issue created
  def self.last_issue_created
    self.find :first, :order => "created_at DESC"
  end
#     todo:look for the last issue published
  def self.last_issue_published
    #TODO: Test the NOW() in Mysql 4 and 5'
    self.find :first, :order => "date_published DESC", :conditions => "status = 1 and date_published <= NOW() "
  end

#   return possible statuses, as an array of strings
  def self.possible_statuses
    @@possible_statuses.keys
  end

#   return possible statuses, as a hash
  def self.possible_statuses_hash
    @@possible_statuses
  end

#   todo:create a default issue ready to fill in with articles
  def self.create_default
  end

#   get the status name from the number of status
  def status_name
    a = @@possible_statuses.invert
    a[self.status.to_i]
  end
  


#     Escaping html
    def before_save
      ERB::Util.h(self.issue_number)
    end
    
    # Prevents deletion unless it contains no sectons
    def before_destroy
      if self.sections.count > 0
        raise "This issue already has sections associated delete them first"
      end
      if self.status == @@possible_statuses["published"]
        raise "You can not delete published issues, change the issue status first and then try again"
      end
    end
    
    def toggle_status
      if self.status == @@possible_statuses["published"]
        self.status = @@possible_statuses["not published"]
      elsif self.status == @@possible_statuses["not published"]
           self.status = @@possible_statuses["published"]       
      else
         raise "Undefined status"
      end
    end
    
    def validate
     # errors.add(:date_published, "can't be in the future if the satatus is published" ) if (status == @@possible_statuses["published"] and date_published > Time.now())
    end
    
    #Layout is YAML string defining the articles that have to be shown in the 
    #front page of the issue
    #for now the format is
    # [{"article"=>article_id, "section"=>section_id}, ...]
    def get_layout
      raise "Undefined layout" if self.layout.nil? or YAML::load(self.layout)== "" or YAML::load(self.layout)== false
      YAML::load(self.layout)  unless self.layout.nil? 
    end
    
    # Set the layout, it recieves an array wiht the format  [{"article"=>article_id, "section"=>section_id}, ...]
    # TODO: for every elemet verifies that the sections belong to the issue and every article 
    # belongs to the given section
    def set_layout(lyt)
      begin
        new_lyt = []
         for element in lyt
            @article = element["article"]
            @section = element["section"]
            raise "Invalid section/article " if(!section_article?(@section, @article))
            new_lyt << {"article"=> @article, "section"=> @section} 
         end
       
       new_lyt = lyt.to_yaml
       self.layout = new_lyt
       return true
       rescue Exception => e
        # If for some reason the layout can't be read
        raise "Invalid section/article: "+lyt.inspect  if(!section_article?(@section, @article))
        return false
      end
    end
    
# Is it ok to show this issue?
  def show?( date )
     if date_published <= date and status == @@possible_statuses['published']
      return true
     else
       return false
     end
  end

  def after_create
    for name in  @@default_sections
      s = Section.new()
      s.name = name
      s.issue = self
      if s.save!
        sections << s
      end
    end
  end

private
  # Does the  issue has this section
  def section?(section_id)
    secs = self.sections
    if secs.member? Section.find(section_id)
      return true 
    else
      return false
    end
  end
  
  def section_article?(section_id, article_id)
  begin
      s = Section.find(section_id)
      a = Article.find(article_id)
  rescue ActiveRecord::RecordNotFound
      return false
  end
     if(self.sections.member? s and s.articles.member? a)
         return true
      else
        return false
      end
  end


end
